#if !defined(PW_PBL_FORMAT_HPP) && defined(PW_PBL_FORMAT)
#	define PW_PBL_FORMAT_HPP

#	include <fmt/format.h>
#	include <fmt/compile.h>
#	include "Meta/String.hpp"
#	include "FloatInt.hpp"
#	include "TLSF.hpp"

namespace pw_pbl::format
{

	using ::fmt::format_string;
	using ::fmt::format_to;
	using ::fmt::format_to_n;
	using ::fmt::formatted_size;
	using ::fmt::formatter;
	using ::fmt::print;
	using ::fmt::println;
	using ::fmt::report_error;

	template <typename... ARGS>
	inline decltype(auto) format(format_string<ARGS...> sfmt, ARGS &&...args)
	{
		std::basic_string<char, std::char_traits<char>, TLSF::TImp<>::Allocator<char>> out;
		::fmt::format_to(std::back_inserter(out), sfmt, std::forward<ARGS>(args)...);
		return out;
	}

#	if FMT_USE_NONTYPE_TEMPLATE_ARGS
	template <pw_pbl::Meta::Str RAW>
	struct compiled_string;

	template <typename CHAR, size_t N, pw_pbl::Meta::Str<CHAR, N> RAW>
	struct compiled_string<RAW> : ::fmt::compiled_string
	{
		using char_type = CHAR;
		explicit constexpr operator ::fmt::basic_string_view<char_type>() const { return {RAW.begin(), RAW.size()}; }
	};
#	endif // FMT_USE_NONTYPE_TEMPLATE_ARGS

} // namespace pw_pbl::format

#	if FMT_USE_NONTYPE_TEMPLATE_ARGS
namespace pw_pbl::Meta::inline literals
{
	template <pw_pbl::Meta::Str FORMAT, pw_pbl::Meta::Auto... PARMS>
	constexpr pw_pbl::Meta::Str MetaFormat = [] {
		using char_type = decltype(FORMAT)::char_type;
		constexpr auto fmt_str = format::compiled_string<FORMAT>{};
		constexpr auto size = ::fmt::formatted_size(fmt_str, PARMS()...);
		char_type buf[size + 1];
		::fmt::format_to(buf, fmt_str, PARMS()...);
		buf[size] = 0;
		return pw_pbl::Meta::Str<char_type, size + 1>{buf};
	}();

} // namespace pw_pbl::Meta::inline literals

namespace pw_pbl
{
	using Meta::MetaFormat;
}
#	endif // FMT_USE_NONTYPE_TEMPLATE_ARGS

template <std::integral REP, auto... DEN>
struct fmt::formatter<pw_pbl::FloatInt<REP, DEN...>>
{
	detail::dynamic_format_specs<char> specs_;

	template <typename ParseContext>
	constexpr auto parse(ParseContext &ctx) -> decltype(ctx.begin())
	{
		auto it = detail::parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, detail::type::float_type);
		if (specs_.type() != presentation_type::none && specs_.type() != presentation_type::general)
			report_error("only support default g format");
		return it;
	}

	template <typename FormatContext>
	constexpr auto format(const pw_pbl::FloatInt<REP, DEN...> &p, FormatContext &ctx) const -> decltype(ctx.out())
	{
		ptrdiff_t numBits;
		constexpr auto EMaxBits = std::numeric_limits<REP>::digits10 + 3;
		std::array<char, EMaxBits> numBuf;
		{
			auto precision = specs_.precision;
			detail::handle_dynamic_spec(specs_.dynamic_precision(), precision, specs_.precision_ref, ctx);
			auto [intPart, decPart] = p.Abs().Get();
			auto pend = fmt::format_to(numBuf.begin(), FMT_COMPILE("{}"), intPart);
			numBits = pend - numBuf.begin();
			assert(numBits < EMaxBits);
			if (auto iszero = intPart == 0 && decPart == 0; iszero ? precision > 0 : precision != 0) // 为0时默认不显示小数部分除非强制要求，不为0时默认显示小数部分除非强制禁止
			{
				*pend++ = '.';
				ptrdiff_t decBits = 0;															  //< 小数部分位数
				auto maxbits = precision < 0 ? std::numeric_limits<ptrdiff_t>::max() : precision; //< 小数部分最大位数
				while (pend < numBuf.end() && decBits < maxbits)
				{
					auto [q, r] = p.DivDen(decPart * 10);
					*pend++ = q + '0';
					decPart = r;
					decBits++;
					if (decPart == 0 && precision < 0)
						break;
				}
				numBits += decBits + 1; // 包含小数点
			}
		}
		bool isNagetive = std::is_signed_v<REP> && p.raw < 0;
		bool bSigned = isNagetive || specs_.sign() == sign::plus || specs_.sign() == sign::space;
		int fillCnt;
		{
			auto width = specs_.width;
			detail::handle_dynamic_spec(specs_.dynamic_width(), width, specs_.width_ref, ctx);
			auto rawBits = bSigned + numBits;
			fillCnt = width > rawBits ? width - rawBits : 0;
		}
		auto it = ctx.out();
		if (fillCnt != 0)
			if (specs_.align() != align::numeric && specs_.align() != align::left)
			{
				auto cnt = specs_.align() == align::center ? fillCnt - fillCnt / 2 : fillCnt; // 不是居中便是右对齐
				for (auto i = cnt; i != 0; i--)
					*it++ = *specs_.fill<typename FormatContext::char_type>();
				fillCnt -= cnt;
			}
		if (bSigned)
			*it++ = isNagetive ? '-' : (specs_.sign() == sign::space ? ' ' : '+');
		if (fillCnt != 0 && specs_.align() == align::numeric)
			for (; fillCnt != 0; fillCnt--)
				*it++ = '0';
		for (ptrdiff_t i = 0; i < numBits; i++)
			*it++ = numBuf[i];
		for (; fillCnt != 0; fillCnt--)
			*it++ = *specs_.fill<typename FormatContext::char_type>();
		return it;
	}
};

#endif // !defined(PW_PBL_FORMAT_HPP) && defined(PW_PBL_FORMAT)
